package com.schedualnew.mq.service;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ewell.sdk.domain.MessageEntity;
import com.schedualnew.mq.config.XRayMQConfig;
import com.schedualnew.mq.dto.esb.AccessControl;
import com.schedualnew.mq.dto.esb.MessageHeader;
import com.schedualnew.mq.dto.esb.xray.pacssource.SourceReceiveESBEntry;
import com.schedualnew.mq.dto.esb.xray.pacssource.SourceSendESBEntry;
import com.schedualnew.mq.dto.esb.xray.schedule.response.XRayResponseMsgDetail;
import com.schedualnew.mq.dto.esb.xray.schedule.response.XRayScheduleResponseESBEntry;
import com.schedualnew.mq.dto.esb.xray.schedule.response.XRayScheduleResponseMsg;
import com.schedualnew.mq.dto.esb.xray.schedule.resquest.XRayScheduleSendESBEntry;
import com.schedualnew.mq.dto.esb.xray.schedule.resquest.XRaySendMsg;
import com.schedualnew.mq.dto.esb.xray.schedule.resquest.XRaySendMsgInfo;
import com.schedualnew.mq.entity.*;
import com.schedualnew.mq.entity.vo.ExamScheduleItemVo;
import com.schedualnew.mq.entity.vo.PACSXRaySourceResultItem;
import com.schedualnew.mq.entity.vo.XRaySource;
import com.schedualnew.mq.entity.vo.XRaySourceItem;
import com.schedualnew.mq.mapper.*;
import com.schedualnew.mq.util.DateUtils;
import com.schedualnew.mq.util.JacksonUtil;
import com.schedualnew.mq.util.JsonUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ljy aka ryan
 * @date 2023/3/20$ 17:06$
 * @description 放射科相关服务功能
 */
@Service
public class XRayService {
    private static final Logger logger = LogManager.getLogger(ScheduleServiceImpl.class);
    final String dateTimeFormatStr = "yyyy-MM-dd HH:mm:ss";
    @Autowired
    private MQClientService mqClientService;

    @Autowired
    private XRayMQConfig xRayMQConfig;
    @Autowired
    @Qualifier("dataSource")
    private DataSource dataSource;

    @Autowired
    private DictExamQueueMapper examQueueMapper;
    @Autowired
    private DictScheduleApmMapper scheduleApmMapper;

    @Autowired
    private DictScheduleCycleMapper scheduleCycleMapper;

    @Autowired
    private ExamScheduleApmMapper examScheduleApmMapper;

    @Autowired
    private DictScheduleApmRegularMapper apmRegularMapper;

    @Autowired
    private DictExamItemMapper dictExamItemMapper;

    @Autowired
    private ExamApplyMapper examApplyMapper;

    @Autowired
    private ExamScheduleItemMapper scheduleItemMapper;

    public void getXRaySourceTest(String xml) {
        // 解析收到的号源剩余数据量
        List<XRaySource> xRaySources = resolveQueueApms(xml);
        // 将队列的号源时段保存导数据库
        storeData(xRaySources, "1");
    }


    public void getXRaySource() {
        List<DictExamQueue> queueList = getRadiologyList(xRayMQConfig.getExamClass());

        if (CollectionUtils.isEmpty(queueList)) {
            logger.error("没有找到需要同步的放射科号源信息!");
            return;
        }

        AccessControl accessControl = new AccessControl();
        accessControl.setUserName(xRayMQConfig.getUserName());
        accessControl.setPassword(xRayMQConfig.getPassword());
        accessControl.setSysFlag("1");
        accessControl.setOrderNo(xRayMQConfig.getGetPACSSourceOrderNo());
        accessControl.setFid(xRayMQConfig.getGetPACSSourceFid());
        MessageHeader header = new MessageHeader();
        header.setFid(xRayMQConfig.getGetPACSSourceFid());
        header.setOrderNo(xRayMQConfig.getGetPACSSourceOrderNo());
        header.setSourceSysCode(xRayMQConfig.getSourceSystemCode());
        header.setTargetSysCode(xRayMQConfig.getGetPACSTargetSysCode());
        header.setReturnFlag("0"); // 需要获取返回值
        header.setHospCode(xRayMQConfig.getHospCode());
        header.setMsgDate(DateUtils.getCurrentDateTime());

        SourceSendESBEntry.RequestOption requestOption = new SourceSendESBEntry.RequestOption();
        requestOption.setTriggerData("0");
        requestOption.setDataAmount("500");

        SourceSendESBEntry.GroupInfo groupInfo = new SourceSendESBEntry.GroupInfo();
        SourceSendESBEntry.GroupInfoAs groupInfoAs = new SourceSendESBEntry.GroupInfoAs();
        groupInfoAs.setId("");
        groupInfoAs.setLinkField("");
        groupInfo.setFlag("0");

        groupInfo.setAs(groupInfoAs);

        SourceSendESBEntry esbEntry = new SourceSendESBEntry();
        esbEntry.setAccessControl(accessControl);
        esbEntry.setMessageHeader(header);
        esbEntry.setMsgInfo(new SourceSendESBEntry.XRayQueryMsgInfo());
        esbEntry.getMsgInfo().setFlag("1");
        esbEntry.setRequestOption(requestOption);
        esbEntry.setGroupInfo(groupInfo);
        for (DictExamQueue examQueue : queueList) {
            try {
                ArrayList<SourceSendESBEntry.QueryItem> queryItems = new ArrayList<>();

                SourceSendESBEntry.QueryItem roomName = new SourceSendESBEntry.QueryItem();
                roomName.setItem("ROOM_NAME");
                roomName.setCompy("=");
                roomName.setValue("'" + examQueue.getQueueName() + "'");
                roomName.setSplice("AND");
                queryItems.add(roomName);

                esbEntry.getMsgInfo().setQuery(queryItems);
                String sendContent = JacksonUtil.toXmlString(esbEntry);

                String entity = mqClientService.pushMsgWithResult(xRayMQConfig.getGetPACSSourceChangeMQ(), xRayMQConfig.getGetPACSSourceChannelId(), sendContent);
                // 解析收到的号源剩余数据量
                //logger.info("开始执行号源返回内容");
                MessageEntity messageEntity = JacksonUtil.readValue(entity, MessageEntity.class);
                if (Objects.isNull(messageEntity)) {
                    logger.error("反序列化字符串失败!");
                    continue;
                }
                //logger.info("需要解析的数据内容");
                List<XRaySource> xRaySources = resolveQueueApms(messageEntity.getMsg());
                int rowCount = 0;
                if (CollectionUtils.isNotEmpty(xRaySources)) {
                    rowCount = xRaySources.size();
                }
                // logger.info("开始执行号源入库操作,数据行数:{}", rowCount);
                // 将队列的号源时段保存导数据库
                storeData(xRaySources, "1");
                // logger.info("源入库操作执行完成！");
            } catch (Exception e) {
                logger.error("队列:{}，获取号源执行异常!{}", examQueue.getQueueName(), JacksonUtil.toJsonString(e));
            }
        }
    }

    /**
     * 获取超声号源信息
     */
    public void getCSSource() {
        List<DictExamQueue> queueList = getRadiologyList(xRayMQConfig.getCs().getExamClass());

        if (CollectionUtils.isEmpty(queueList)) {
            logger.error("没有找到需要同步的超声号源信息!");
            return;
        }

        AccessControl accessControl = new AccessControl();
        accessControl.setUserName(xRayMQConfig.getUserName());
        accessControl.setPassword(xRayMQConfig.getPassword());
        accessControl.setSysFlag("1");
        accessControl.setOrderNo(xRayMQConfig.getCs().getSource().getOrderNo());
        accessControl.setFid(xRayMQConfig.getCs().getSource().getFid());
        MessageHeader header = new MessageHeader();
        header.setFid(xRayMQConfig.getCs().getSource().getFid());
        header.setOrderNo(xRayMQConfig.getCs().getSource().getOrderNo());
        header.setSourceSysCode(xRayMQConfig.getSourceSystemCode());
        header.setTargetSysCode(xRayMQConfig.getGetPACSTargetSysCode());
        header.setReturnFlag("0"); // 需要获取返回值
        header.setHospCode(xRayMQConfig.getHospCode());
        header.setMsgDate(DateUtils.getCurrentDateTime());

        SourceSendESBEntry.RequestOption requestOption = new SourceSendESBEntry.RequestOption();
        requestOption.setTriggerData("0");
        requestOption.setDataAmount("500");

        SourceSendESBEntry.GroupInfo groupInfo = new SourceSendESBEntry.GroupInfo();
        SourceSendESBEntry.GroupInfoAs groupInfoAs = new SourceSendESBEntry.GroupInfoAs();
        groupInfoAs.setId("");
        groupInfoAs.setLinkField("");
        groupInfo.setFlag("0");

        groupInfo.setAs(groupInfoAs);

        SourceSendESBEntry esbEntry = new SourceSendESBEntry();
        esbEntry.setAccessControl(accessControl);
        esbEntry.setMessageHeader(header);
        esbEntry.setMsgInfo(new SourceSendESBEntry.XRayQueryMsgInfo());
        esbEntry.getMsgInfo().setFlag("1");
        esbEntry.setRequestOption(requestOption);
        esbEntry.setGroupInfo(groupInfo);
        for (DictExamQueue examQueue : queueList) {
            try {
                ArrayList<SourceSendESBEntry.QueryItem> queryItems = new ArrayList<>();

                SourceSendESBEntry.QueryItem roomName = new SourceSendESBEntry.QueryItem();
                roomName.setItem("ROOM_ID");
                roomName.setCompy("=");
                roomName.setValue(examQueue.getRoomId());
                roomName.setSplice("AND");
                queryItems.add(roomName);

                esbEntry.getMsgInfo().setQuery(queryItems);
                String sendContent = JacksonUtil.toXmlString(esbEntry);

                String entity = mqClientService.pushMsgWithResult(xRayMQConfig.getCs().getSource().getChangeMQ(), xRayMQConfig.getCs().getSource().getChannelId(), sendContent);
                // 解析收到的号源剩余数据量
                //logger.info("开始执行号源返回内容");
                MessageEntity messageEntity = JacksonUtil.readValue(entity, MessageEntity.class);
                if (Objects.isNull(messageEntity)) {
                    logger.error("反序列化字符串失败!");
                    continue;
                }
                //logger.info("需要解析的数据内容");
                List<XRaySource> xRaySources = resolveQueueApms(messageEntity.getMsg());
//                int rowCount = 0;
//                if (CollectionUtils.isNotEmpty(xRaySources)) {
//                    rowCount = xRaySources.size();
//                }
                // logger.info("开始执行号源入库操作,数据行数:{}", rowCount);
                // 将队列的号源时段保存导数据库
                storeData(xRaySources, "2");
                // logger.info("源入库操作执行完成！");
            } catch (Exception e) {
                logger.error("队列:{}，获取号源执行异常!{}", examQueue.getQueueName(), JacksonUtil.toJsonString(e));
            }
        }
    }


    /**
     * 发送
     */
    public void sendXRayScheduleMsg(ExamScheduleItemVo scheduleItemVo, String applyNo) {
        // 未开启不推送
        if (!xRayMQConfig.getEnable()) {
            return;
        }
        /**
         *  1. 判断预约的项目是否放射科的检查
         *  2. 构造发送消息内容
         *  3. 发送并接收结果
         *  4. 将需要的信息落库
         */
        List<String> examClassList = Arrays.asList(xRayMQConfig.getExamClass().split(","));
        QueryWrapper<DictExamItem> itemQueryWrapper = new QueryWrapper<>();
        itemQueryWrapper.in("EXAM_CLASS", examClassList);
        itemQueryWrapper.eq("ITEM_CODE", scheduleItemVo.getItemCode());
        List<DictExamItem> examItems = dictExamItemMapper.selectList(itemQueryWrapper);
        // 如果返回为空说明不是放射科的检查项目，直接返回
        if (CollectionUtils.isEmpty(examItems)) {
            logger.info("没有获取到需要推送放射科的预约数据:{}", scheduleItemVo.getItemCode());
            return;
        }
        String dateTimeNow = DateUtil.format(new Date(), dateTimeFormatStr);
        // 构造发送的参数
        XRayScheduleSendESBEntry<XRaySendMsgInfo<XRayResponseMsgDetail>> sendESBEntry = new XRayScheduleSendESBEntry<>();
        MessageHeader header = new MessageHeader();

        header.setFid(xRayMQConfig.getPushPACSScheduleFid());
        header.setMsgDate(dateTimeNow);
        header.setOrderNo(xRayMQConfig.getPushPACSScheduleOrderNo());
        header.setTargetSysCode(xRayMQConfig.getPushPACSTargetSysCode());
        header.setSourceSysCode(xRayMQConfig.getSourceSystemCode());
        header.setReturnFlag("0");
        header.setHospCode(xRayMQConfig.getHospCode());

        AccessControl accessControl = new AccessControl();
        accessControl.setFid(xRayMQConfig.getPushPACSScheduleFid());
        accessControl.setOrderNo(xRayMQConfig.getPushPACSScheduleOrderNo());
        accessControl.setSysFlag("1");
        accessControl.setUserName(xRayMQConfig.getUserName());
        accessControl.setPassword(xRayMQConfig.getPassword());

        sendESBEntry.setAccessControl(accessControl);
        sendESBEntry.setMessageHeader(header);

        QueryWrapper<DictExamQueue> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("QUEUE_NAME", scheduleItemVo.getQueueName());
        DictExamQueue examQueue = examQueueMapper.selectOne(queryWrapper);
        if (Objects.isNull(examQueue)) {
            logger.error("没有找到队列名称为： " + scheduleItemVo.getQueueName() + "  的队列字典设置!");
            return;
        }

        XRayResponseMsgDetail detail = new XRayResponseMsgDetail();
        detail.setEquisitionNo(applyNo);

        XRaySendMsgInfo<XRayResponseMsgDetail> sendMsgInfo = new XRaySendMsgInfo<>();
        XRaySendMsg<XRayResponseMsgDetail> sendMsg = new XRaySendMsg<>();
        sendMsg.setId("1");
        sendMsg.setAction("insert");
        sendMsg.setLastUpdate(dateTimeNow);
        sendMsg.setDetail(Arrays.asList(detail));
        sendMsg.setExamCategCode(examQueue.getDeviceType());
        sendMsg.setExamCategName(examQueue.getDeviceType());
        sendMsg.setRoomId(examQueue.getRoomId());
        String[] timeLists;
        if (StringUtils.isNoneBlank(scheduleItemVo.getScheduleApm())) {
            if (scheduleItemVo.getScheduleApm().contains("-")) {
                timeLists = scheduleItemVo.getScheduleApm().split("-");
            } else {
                timeLists = scheduleItemVo.getScheduleApm().split("~");
            }
        } else {
            timeLists = new String[2];
            timeLists[0] = "";
            timeLists[1] = "";
        }

        sendMsg.setReserveExamDate(scheduleItemVo.getScheduledDate() + " " + timeLists[0]);
        sendMsgInfo.setMsg(sendMsg);

        sendESBEntry.setMsgInfo(sendMsgInfo);
        String xml = JacksonUtil.toXmlString(sendESBEntry);

        logger.info("预约推送PACS-sendXRayScheduleMsg:{}", xml);
        MessageEntity messageEntity = mqClientService.pushMsgWithResult2(xRayMQConfig.getPushPACSScheduleChangeMQ(), xRayMQConfig.getPushPACSScheduleChannelId(), xml);
        // 发送成功
        if (StringUtils.isNoneBlank(messageEntity.getMsg())) {
            XRayScheduleResponseESBEntry esbEntry =
                    JacksonUtil.readXmlValue(messageEntity.getMsg(), XRayScheduleResponseESBEntry.class);
            if (Objects.isNull(esbEntry) || Objects.isNull(esbEntry.getMsgInfo())) {
                logger.error("预约推送PACS失败内容为空!{}", esbEntry);
                return;
            }
            /*
             * 1. 判断发送是否成功
             */
            XRayScheduleResponseMsg msg = esbEntry.getMsgInfo().getMsg();
            // 申请单号
            List<String> applyNos = msg.getDetails().stream()
                    .map(XRayResponseMsgDetail::getEquisitionNo)
                    .filter(StringUtils::isNoneBlank).collect(Collectors.toList());

            // 更新 预约的影像号和排队号
            List<ExamScheduleItem> examScheduleItems = examApplyMapper.getExamScheduleItemByApplyNos(applyNos);
            for (ExamScheduleItem item : examScheduleItems) {
                item.setImageNo(msg.getImageNo());
                item.setPacsSortNo(msg.getNo());
                item.setPacsExamDept(msg.getTriageExamDept());
                logger.info("PACS返回影像号数据:{}", JacksonUtil.toJsonString(item));
                scheduleItemMapper.updateById(item);
            }
        } else {
            // 异常 重新推送
            messageEntity = mqClientService.pushMsgWithResult2(xRayMQConfig.getPushPACSScheduleChangeMQ(), xRayMQConfig.getPushPACSScheduleChannelId(), xml);
            if ("0".equals(messageEntity.getEsbEntry().getRetInfo().getRetCode())) {
                XRayScheduleResponseESBEntry esbEntry =
                        JacksonUtil.readXmlValue(messageEntity.getMsg(), XRayScheduleResponseESBEntry.class);
                if (Objects.isNull(esbEntry) || Objects.isNull(esbEntry.getMsgInfo())) {
                    return;
                }
                /*
                 * 1. 判断发送是否成功
                 */
                XRayScheduleResponseMsg msg = esbEntry.getMsgInfo().getMsg();
                // 申请单号
                List<String> applyNos = msg.getDetails().stream()
                        .map(XRayResponseMsgDetail::getEquisitionNo)
                        .filter(StringUtils::isNoneBlank).collect(Collectors.toList());
                // 更新 预约的影像号和排队号
                List<ExamScheduleItem> examScheduleItems = examApplyMapper.getExamScheduleItemByApplyNos(applyNos);
                for (ExamScheduleItem item : examScheduleItems) {
                    item.setImageNo(msg.getImageNo());
                    item.setPacsSortNo(msg.getNo());
                    item.setPacsExamDept(msg.getTriageExamDept());
                    logger.info("重试!PACS返回影像号数据:{}", JacksonUtil.toJsonString(item));
                    scheduleItemMapper.updateById(item);
                }
            }
        }
    }

    /**
     * 发送取消信息
     */
    public void sendXRayScheduleCancelMsg() {

    }


    /**
     * 获取放射科检查队列
     * 根据检查类别获取队列列表
     * xRayMQConfig.getExamClass()
     *
     * @return
     */
    public List<DictExamQueue> getRadiologyList(String examClassStr) {
        QueryWrapper<DictExamQueue> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(examClassStr)) {
            String[] examClass = examClassStr.split(",");
            queryWrapper.in("EXAM_CLASS", examClass);
        }
        queryWrapper.isNotNull("ROOM_ID");
        queryWrapper.isNotNull("DEVICE_TYPE");

        return examQueueMapper.selectList(queryWrapper);
    }

    /**
     * 解析队列的时段列表 可用的数量和总的数量
     *
     * @return
     */
    private List<XRaySource> resolveQueueApms(String entity) {
        // 执行 解析号源数据
        List<XRaySource> resultList = new ArrayList<>();
        if (StringUtils.isBlank(entity)) {
            return resultList;
        }
        SourceReceiveESBEntry esbEntry = JacksonUtil.readXmlValue(entity, SourceReceiveESBEntry.class);
        if (Objects.isNull(esbEntry)
                || Objects.isNull(esbEntry.getRetInfo())
                || esbEntry.getRetInfo().getRetCode().equals("0")
                || CollectionUtils.isEmpty(esbEntry.getMsgList())) {
            return resultList;
        }
        for (String item : esbEntry.getMsgList()) {
            item = item.replace("![CDATA[", "").replace("]]", "")
                    .replace("<msg>", "").replace("</msg>", "")
                    .replace("<body>", "").replace("</body>", "");

            PACSXRaySourceResultItem resultItem = JacksonUtil.readXmlValue(item, PACSXRaySourceResultItem.class);
            String dateTime = resultItem.getTimeSeg().replace(": ", ":");
            String[] dateTimeArr = dateTime.split(" ");
            String dataStr = dateTimeArr[0];
            XRaySource source = resultList.stream()
                    .filter(x -> dataStr.equals(x.getDate()))
                    .findFirst().orElse(null);
            if (Objects.isNull(source)) {
                source = new XRaySource();
                source.setApms(new ArrayList<>());
                source.setDate(dataStr);
                source.setRoomId(resultItem.getRoomId());
                source.setRoomName(resultItem.getRoomName());
                source.setEquipmentType(resultItem.getEquipmentType());
            } else {
                resultList.remove(source);
            }
            XRaySourceItem apmItem = new XRaySourceItem();
            apmItem.setTimeStart(dateTimeArr[1]);
            apmItem.setLimitNum(resultItem.getLimitNum());
            apmItem.setRemainingNum(resultItem.getRemainingNum());
            source.getApms().add(apmItem);

            resultList.add(source);
        }

        return resultList;
    }

    /**
     * 将pacs的时段数据存储到数据库中
     *
     * @param xRaySources
     * @param from        1: 放射科 2:超声科
     * @return
     */
    private Boolean storeData(List<XRaySource> xRaySources, String from) {
        if (CollectionUtils.isEmpty(xRaySources)) {
            logger.error("放射科号源数据解析为空！");
            return false;
        }
        QueryWrapper<DictScheduleCycle> scheduleCycleQueryWrapper = new QueryWrapper<>();
        scheduleCycleQueryWrapper.eq("QUEUE_NAME", xRaySources.get(0).getRoomName());
        scheduleCycleQueryWrapper.eq("CYCLE_TYPE", "2");

        List<DictScheduleCycle> cycles = scheduleCycleMapper.selectList(scheduleCycleQueryWrapper);
        if (CollectionUtils.isEmpty(cycles)) {
            logger.error("{},没有查询到号源周期:", xRaySources.get(0).getRoomName());
            return false;
        }
        DictScheduleCycle cycle = cycles.get(0);

        /**
         * 1. 查询队列的时段号源设置字典
         * 2. 对比数据进行增、改(禁用、启用、设置预约总量
         * 3. 修改已预约的数据量 进行数量限制( 只能改大
         */
        List<String> dateList = xRaySources.stream().map(x -> x.getDate()).collect(Collectors.toList());

        QueryWrapper<DictScheduleApm> dictScheduleApmQueryWrapper = new QueryWrapper<>();
        dictScheduleApmQueryWrapper.eq("QUEUE_NAME", xRaySources.get(0).getRoomName());
        dictScheduleApmQueryWrapper.in("SCHEDULE_DATE", dateList);

        List<DictScheduleApm> dictScheduleApms = scheduleApmMapper.selectList(dictScheduleApmQueryWrapper);
        // 新增
        // List<DictScheduleApm> newScheduleApms = new ArrayList<>();
        // 逐个添加
        if (CollectionUtils.isEmpty(dictScheduleApms)) {
            for (XRaySource source : xRaySources) {
                for (XRaySourceItem item : source.getApms()) {
                    DictScheduleApm apm = createNewDictScheudleApm(cycle, source, item, from);
                    if (Objects.isNull(apm)) {
                        continue;
                    }
                    scheduleApmMapper.insert(apm);
                }
            }
        } else {
            // 新增、修改
            for (XRaySource raySource : xRaySources) {
                for (XRaySourceItem apmItem : raySource.getApms()) {
                    DictScheduleApm scheduleApm = dictScheduleApms.stream()
                            .filter(x -> Objects.equals(x.getScheduleDate(), raySource.getDate())
                                    && Objects.equals(apmItem.getTimeStart(), x.getTimeStart()))
                            .findFirst().orElse(null);
                    if (Objects.isNull(scheduleApm)) {
                        scheduleApm = createNewDictScheudleApm(cycle, raySource, apmItem, from);
                        if (Objects.isNull(scheduleApm)) {
                            continue;
                        }
                        scheduleApmMapper.insert(scheduleApm);
                    } else {
                        double maxLimit = Double.parseDouble(apmItem.getLimitNum());
                        double remainingNum = Double.parseDouble(apmItem.getRemainingNum());

                        // 更新最大限制系数
                        if (maxLimit != scheduleApm.getMaxLimit()) {
                            scheduleApm.setMaxLimit(maxLimit);
                            scheduleApm.setStopFlag("0");

                            UpdateWrapper<DictScheduleApm> updateWrapper = new UpdateWrapper<>();
                            updateWrapper.eq("APM_CODE", scheduleApm.getApmCode());
                            updateWrapper.eq("SCHEDULE_DATE", scheduleApm.getScheduleDate());
                            updateWrapper.set("STOP_FLAG", scheduleApm.getStopFlag());
                            updateWrapper.set("MAX_LIMIT", scheduleApm.getMaxLimit());
                            scheduleApmMapper.update(null, updateWrapper);
                        }

                        if (maxLimit > remainingNum) {
                            // 修改已预约数量
                            updateScheduleCount(maxLimit, remainingNum, scheduleApm);
                        }
                    }
                }
            }
            // 禁用-原来有现在没有的时段
            for (DictScheduleApm next : dictScheduleApms) {
                for (XRaySource source : xRaySources) {
                    XRaySourceItem orElse = source.getApms().stream()
                            .filter(x -> Objects.equals(next.getScheduleDate(), source.getDate()) && Objects.equals(next.getTimeStart(), x.getTimeStart()))
                            .findFirst().orElse(null);
                    // 进行禁用操作
                    if (Objects.isNull(orElse)) {
                        next.setStopFlag("0");
                        UpdateWrapper<DictScheduleApm> updateWrapper = new UpdateWrapper<>();
                        // 禁用操作
                        updateWrapper.set("STOP_FLAG", "0");
                        updateWrapper.eq("APM_CODE", next.getApmCode());
                        updateWrapper.eq("SCHEDULE_DATE", next.getScheduleDate());

                        scheduleApmMapper.update(null, updateWrapper);
                    }
                }
            }
        }
        return true;
    }

    /**
     * 根据周期和放射科号源 创建系统时段
     * 如果不需要同步的时段直接返回为空 不用插入
     *
     * @param cycle
     * @param source
     * @param item
     * @param from
     * @return
     */
    private DictScheduleApm createNewDictScheudleApm(DictScheduleCycle cycle,
                                                     XRaySource source,
                                                     XRaySourceItem item,
                                                     String from) {
        int timeSpanMinutes = 30;

        double maxLimit = Double.parseDouble(item.getLimitNum());
        double remainingNum = Double.parseDouble(item.getRemainingNum());

        Date dateStart = DateUtils.parse(source.getDate() + " " + item.getTimeStart(), "yyyy-MM-dd HH:mm:ss");
        Date dateEnd = DateUtils.addMinutes(dateStart, timeSpanMinutes);
        String dateTimeStart = DateUtils.format(dateStart, "HH:mm");
        String dateTimeEnd = DateUtils.format(dateEnd, "HH:mm");

        // 实际的结束时间需要减1s
        Date datetimeEnd = DateUtils.addSecond(dateEnd, -1);
        String datetimeStartStr2 = DateUtils.format(dateStart, "HH:mm:ss");
        String datetimeEndStr2 = DateUtils.format(datetimeEnd, "HH:mm:ss");

        String queueApm = dateTimeStart + "-" + dateTimeEnd;
        // 时段标识
        String apmFlag = xRayMQConfig.getApmCode(dateTimeStart);

        String apmCode = getSerialId("APM_CODE", null);
        DictScheduleApm apm = new DictScheduleApm();
        apm.setStopFlag("0");
        // 时段午别
        apm.setDateStart(cycle.getDateStart());
        apm.setDateEnd(cycle.getDateEnd());
        apm.setMaxLimit(maxLimit);
        apm.setScheduleDate(source.getDate());
        apm.setQueueName(source.getRoomName());
        apm.setApmCode(apmCode);
        apm.setApmLength(timeSpanMinutes);
        apm.setScheduleApm(queueApm);
        // 将中划线改成波浪线
        apm.setQueueApm(queueApm.replace("-", "~"));
        apm.setTimeStart(datetimeStartStr2);
        apm.setTimeEnd(datetimeEndStr2);
        apm.setApmFlag(apmFlag);

        // 已预约的数量 - 更新已预约的数量
        if (maxLimit > remainingNum) {
            updateScheduleCount(maxLimit, remainingNum, apm);
        }
        // 获取对应的规则id
        String regularId = "";
        List<XRayMQConfig.RegularQueueMap> regularMapsList = null;

        // 超声和放射科 是单独的配置，需要从不同的地方获取配置值
        if ("1".equals(from)) {
            regularMapsList = xRayMQConfig.getRegularMaps();
        } else if ("2".equals(from)) {
            regularMapsList = xRayMQConfig.getCs().getSource().getRegularMaps();
        }

        if (CollectionUtils.isNotEmpty(regularMapsList)) {
            XRayMQConfig.RegularQueueMap queueMap = regularMapsList
                    .stream().filter(x -> x.getQueueName().equals(apm.getQueueName())).findFirst()
                    .orElse(null);

            int weekDay = DateUtils.getWeekDay(source.getDate());
            // 判断同步的日期是不是在需要同步的范围内，如果不在范围内状态设置成停用状态,需要时手动启动
            if (Objects.nonNull(queueMap) && StringUtils.isNotBlank(queueMap.getWeeks())) {
                List<Integer> weeks = JsonUtil.json2List(queueMap.getWeeks(), Integer.class);
                if (!weeks.contains(weekDay)) {
                    apm.setStopFlag("1");
                }
            }

            if (Objects.nonNull(queueMap) && CollectionUtils.isNotEmpty(queueMap.getApmMap())) {

                List<XRayMQConfig.RegularMapApmItem> apmItems = queueMap.getApmMap().stream()
                        // 过滤掉不符合周日期的条件
                        .filter(y -> CollectionUtils.isNotEmpty(y.getWeekIds()) && y.getWeekIds().contains(weekDay))
                        .collect(Collectors.toList());
                // 如果日期没有在需要同步的周数内,禁用时段
                if (CollectionUtils.isEmpty(apmItems)) {
                    return null;
                }

                if (apmItems.size() > 1) {
                    // 过滤掉不符合的时间段配置
                    List<Date> dates = apmItems.stream()
                            .map(x -> DateUtils.parse(source.getDate() + " " + x.getStartTime() + ":00", "yyyy-MM-dd HH:mm:ss"))
                            .filter(x -> {
                                // Date startTimeConf = DateUtils.parse(source.getDate() + " " + x.getStartTime() + ":00", "yyyy-MM-dd HH:mm:ss");
                                // 时段开始时间在配置开始时间之后的使用最晚的一条规则
                                return Objects.nonNull(x) && Objects.nonNull(dateStart) &&
                                        (dateStart.after(x) || x.getTime() == dateStart.getTime());
                            }).collect(Collectors.toList());
                    // 获取到时间列表之后 从中间找出最大的时间，根据最大的时间时分 匹配配置列表获取到规则ID
                    if (CollectionUtils.isNotEmpty(dates)) {
                        Date max = Collections.max(dates);
                        String startTime = DateUtils.format(max, "HH:mm");
                        XRayMQConfig.RegularMapApmItem apmItem = apmItems
                                .stream().filter(x -> x.getStartTime().equals(startTime))
                                .findFirst().orElse(null);
                        if (Objects.nonNull(apmItem)) {
                            regularId = apmItem.getRegularId();
                        }
                    }
                } else {
                    regularId = apmItems.get(0).getRegularId();
                }
            }
        }
        // 一个时段多个规则ID
        if (StringUtils.isNotBlank(regularId)) {
            String[] ids = regularId.split(",");
            for (String id : ids) {
                // 新增时段规则
                DictScheduleApmRegular dictScheduleApmRegular = new DictScheduleApmRegular();
                dictScheduleApmRegular.setApmCode(apm.getApmCode());
                dictScheduleApmRegular.setStopFlag("0");
                dictScheduleApmRegular.setRegularId(id);
                apmRegularMapper.insert(dictScheduleApmRegular);
            }
        }
        return apm;
    }

    /**
     * 更新已预约数量
     *
     * @param maxLimit
     * @param remainingNum
     * @param apm
     */
    private void updateScheduleCount(double maxLimit, double remainingNum, DictScheduleApm apm) {
        /**
         * 1. 获取预约数量列表
         */
        QueryWrapper<ExamScheduleApm> examScheduleWrapper = new QueryWrapper<>();
        examScheduleWrapper.eq("APM_CODE", apm.getApmCode());
        examScheduleWrapper.eq("SCHEDULE_DATE", apm.getScheduleDate());

        ExamScheduleApm examScheduleApm = examScheduleApmMapper.selectOne(examScheduleWrapper);
        if (Objects.isNull(examScheduleApm)) {
            int countVa = new BigDecimal(String.valueOf(maxLimit - remainingNum)).intValue();
            examScheduleApm = new ExamScheduleApm();
            examScheduleApm.setApmCode(apm.getApmCode());
            examScheduleApm.setScheduleDate(apm.getScheduleDate());
            examScheduleApm.setCount(countVa);
            examScheduleApm.setOrgans(Double.parseDouble(String.valueOf(countVa)));
            examScheduleApm.setStopFlag("0");
            examScheduleApmMapper.insert(examScheduleApm);
        } else {
            int countVa = new BigDecimal(String.valueOf(maxLimit - remainingNum)).intValue();
            examScheduleApm.setCount(countVa);

            UpdateWrapper<ExamScheduleApm> update = new UpdateWrapper<>();
            update.eq("APM_CODE", apm.getApmCode());
            update.eq("SCHEDULE_DATE", apm.getScheduleDate());
            update.set("COUNT", countVa);
            update.set("ORGANS", Double.parseDouble(String.valueOf(countVa)));

            examScheduleApmMapper.update(null, update);
        }
    }


    public String getSerialId(String serialName, String pre) {
        DictSerial serial = getDictSerial(serialName);
        Long currentValue = serial.getCurrentValue();
        Integer length = serial.getSerialLength();
        if (currentValue == null && length == null) {
            logger.error("生成主键失败！序列字典表DICT_SERIAL不存在名称为[{}]的记录。", serialName);
        }
        String id = (StringUtils.isBlank(pre) ? "" : pre) + String.format("%0" + length + "d", currentValue);
        return id;
    }

    public DictSerial getDictSerial(String serialName) {
        synchronized (this) {
            while (true) {
                Connection connect = null;
                Statement stmt = null;
                DictSerial serial = new DictSerial();
                try {
                    connect = dataSource.getConnection();
                    connect.setAutoCommit(false);
                    stmt = connect.createStatement();
                    stmt.addBatch("lock table dict_serial in exclusive mode");
                    stmt.executeBatch();
                    stmt.executeUpdate("update dict_serial set current_value=current_value+1 where serial_name='" + serialName + "'");
                    ResultSet resultSet = stmt.executeQuery("select serial_name serialName, current_value currentValue, serial_length serialLength from dict_serial where serial_name='" + serialName + "' ");
                    if (resultSet != null && resultSet.next()) {
                        serial.setSerialName(resultSet.getString("serialName"));
                        serial.setCurrentValue(resultSet.getLong("currentValue"));
                        serial.setSerialLength(resultSet.getInt("serialLength"));
                    }
                    connect.commit();
                    return serial;
                } catch (SQLException e2) {
                    logger.error(e2.getMessage(), e2);
                    if (connect != null) {
                        try {
                            connect.rollback();
                        } catch (SQLException e1) {
                            logger.error(e1.getMessage(), e1);
                        }
                    }
                    try {
                        if (stmt != null) {
                            stmt.close();
                        }
                        if (connect == null) {
                            continue;
                        }
                        connect.close();
                    } catch (Exception e3) {
                        logger.error(e3.getMessage(), e3);
                    }
                } finally {
                    try {
                        if (stmt != null) {
                            stmt.close();
                        }
                        if (connect != null) {
                            connect.close();
                        }
                    } catch (Exception e4) {
                        logger.error(e4.getMessage(), e4);
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        XRayService service = new XRayService();
        String entity = "";
        MessageEntity messageEntity = JacksonUtil.readValue(entity, MessageEntity.class);
//        logger.info("需要解析的数据内容:" + messageEntity.getMsg());
        List<XRaySource> xRaySources = service.resolveQueueApms(messageEntity.getMsg());

        String configStr = "{'queueName':'二住16诊室NT',\n" +
                "                  'apmMap':[{'startTime':'07:00','regularId':'000162','weeks': '[6,7]'}],\n" +
                "                  'weeks': '[6,7]'\n" +
                "                  }\n" +
                "                ]";

        // 将队列的号源时段保存导数据库
        //storeData(xRaySources, "2");

    }

}